// 定义按键输入的结构体 EFI_INPUT_KEY
struct EFI_INPUT_KEY {
    unsigned short ScanCode;    // 按键的扫描码，标识物理按键的位置
    unsigned short UnicodeChar; // 按键对应的 Unicode 字符
};

// 定义 EFI 系统表结构体 EFI_SYSTEM_TABLE
struct EFI_SYSTEM_TABLE {
    char _buf1[44];    // 占位符，用于对齐或跳过前面44字节的无关内容

    // 定义简单文本输入协议的结构体 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
    struct EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
        unsigned long long _buf;  // 占位符，跳过不重要的部分
        // 函数指针，指向 ReadKeyStroke 函数
        unsigned long long (*ReadKeyStroke)(
            struct EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,   // 指向当前输入协议结构体的指针
            struct EFI_INPUT_KEY *Key);                    // 指向存储按键输入的结构体指针
    } *ConIn;  // 输入设备协议的指针，通常指向控制台输入

    unsigned long long _buf2;  // 占位符，跳过不重要的部分

    // 定义简单文本输出协议的结构体 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
    struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
        unsigned long long _buf;  // 占位符，跳过不重要的部分
        // 函数指针，指向 OutputString 函数，用于输出字符串到屏幕
        unsigned long long (*OutputString)(
            struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,  // 指向当前输出协议结构体的指针
            unsigned short *String);                       // 指向要输出的 Unicode 字符串
        unsigned long long _buf2[4];  // 占位符，跳过不重要的部分
        // 函数指针，指向 ClearScreen 函数，用于清屏
        unsigned long long (*ClearScreen)(
            struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This); // 指向当前输出协议结构体的指针
    } *ConOut;  // 输出设备协议的指针，通常指向控制台输出
};

// efi_main 函数是 UEFI 应用程序的入口函数
void efi_main(void *ImageHandle __attribute__ ((unused)),
          struct EFI_SYSTEM_TABLE *SystemTable)  // 接受一个指向系统表的指针
{
    struct EFI_INPUT_KEY key;  // 创建一个 EFI_INPUT_KEY 结构体，用于存储按键信息
    unsigned short str[3];     // 一个 3 个字符的数组，用于存储输出字符串

    // 调用 ConOut 协议中的 ClearScreen 函数来清除屏幕
    SystemTable->ConOut->ClearScreen(SystemTable->ConOut);

    // 无限循环，持续监听按键输入并输出到屏幕
    while (1) {
        // 调用 ConIn 协议的 ReadKeyStroke 函数读取按键输入
        // 如果有按键被按下并成功读取，函数返回 0（表示成功）
        if (!SystemTable->ConIn->ReadKeyStroke(SystemTable->ConIn, &key)) {
            // 如果读取到的按键不是回车键 ('\r')
            if (key.UnicodeChar != L'\r') {
                str[0] = key.UnicodeChar;  // 将按键的 Unicode 字符存储到 str[0]
                str[1] = L'\0';            // 字符串以 '\0' 结束
            } else {
                // 如果按键是回车 ('\r')，则在屏幕上显示换行符
                str[0] = L'\r';  // 存储回车符
                str[1] = L'\n';  // 存储换行符
                str[2] = L'\0';  // 字符串以 '\0' 结束
            }
            // 调用 ConOut 协议的 OutputString 函数将字符输出到屏幕
            SystemTable->ConOut->OutputString(SystemTable->ConOut, str);
        }
    }
}
